(function (zn) {
    var __global = zn.GLOBAL,
        __doc = __global.document;

    var Component = zn.ui.core.Component;

    var __ready = {
        topFrame: null,
        hasReady: false,
        task: [],
        ready: function (handler){
            return this.task.push(handler), this.isReady();
        },
        clear: function (){
            return this.task.length = 0, this;
        },
        exec: function (){
            var _len = this.task.length;
            for(var i = 0; i<_len; i++ ){
                this.task[i].call(zn.GLOBAL, zn);
            }
        },
        isLoaded: function (event){
            return (event || __global.event).type === 'load';
        },
        isReady: function (){
            return this.hasReady || __doc.readyState === "complete";
        },
        fireReady: function (){
            this.exec();
            this.clear();
        },
        completed: function (event){
            if (this.isReady() || this.isLoaded(event)) {
                this.hasReady = true;
                this.detachLoaded();
                this.fireReady();
            }
        },
        setTopFrame: function (){
            try {
                this.topFrame = (__doc.frameElement === null && __doc.documentElement);
            } catch (e) {

            }
        },
        doScroll: function (){
            var _topFrame = this.topFrame;
            if (_topFrame && _topFrame.doScroll) {
                try {
                    // Use the trick by Diego Perini
                    // http://javascript.nwbox.com/IEContentLoaded/
                    _topFrame.doScroll("left");
                } catch (e) {
                    return setTimeout(this.doScroll.bind(this), 50);
                }

                this.fireReady();
            }
        },
        detachLoaded: function (){
            if (__doc.removeEventListener) {
                __doc.removeEventListener("DOMContentLoaded", this.completed.bind(this), false);
                __global.removeEventListener("load", this.completed.bind(this), false);
            } else {
                __doc.detachEvent("onreadystatechange", this.completed.bind(this));
                __global.detachEvent("onload", this.completed.bind(this));
            }
        },
        attachLoaded: function (){
            if (this.isAttached){
                return false;
            }
            if (__doc.addEventListener) {
                __doc.addEventListener('DOMContentLoaded', this.completed.bind(this), false);
                __global.addEventListener('load', this.completed.bind(this), false);
            } else {
                __doc.attachEvent("onreadystatechange", this.completed.bind(this));
                __global.attachEvent("onload", this.completed.bind(this));
                this.setTopFrame();
                this.doScroll();
            }
            (new Component(__doc.body)).scan();
            this.isAttached = true;
        },
        main: function (){
            if (__doc.readyState === "complete") {
                return setTimeout(this.main.bind(this));
            } else {
                this.attachLoaded();
            }
        }
    }

    zn.ready = function (handler){
        var _isReady = __ready.ready(handler);
        if (_isReady) {
            setTimeout(__ready.fireReady.bind(__ready), 1);
        } else {
            __ready.main();
        }
    }

})(zn);